#ifndef __EQUATION_H__
#define __EQUATION_H__

#include <valarray>
#include <functional>
#include <iostream>

typedef std::valarray<double> Vector;

double f(double x);
double u(double x);

double MaxNorm(const Vector& v);
double SquareNorm(const Vector& v);
const Vector GetBoundary(std::function<double(double x)> _u = u);

class SymmetricTridiagonal
{
protected:
	int n;
	Vector diag;
	Vector alpha;

public:
	SymmetricTridiagonal(int _n);
	SymmetricTridiagonal(int _n, double d, double a);
	SymmetricTridiagonal(int _n, const Vector& d, const Vector& a);
	virtual ~SymmetricTridiagonal() = default;
	const Vector operator*(Vector& x) const;
	const Vector& GetDiag() const;
	const Vector& GetAlpha() const;
};

class PossionMatrix : public SymmetricTridiagonal
{
public:
	PossionMatrix(int _n);
	~PossionMatrix() = default;
};

class RHS
{
private:
	int n;
	Vector v;

public:
	RHS() = default;
	RHS(int _n, double left_boundary = 0, double right_boundary = 0, std::function<double(double x)> func = f);
	~RHS() = default;
	const Vector& GetVector() const;
	const int GetSize() const;
	double& operator[](std::size_t i);
};



class WeightedJacobi
{
private:
	int n;
	double omega;
	SymmetricTridiagonal T;
	Vector c;

public:
	WeightedJacobi(const PossionMatrix& A, const Vector& _f, double _omega = 2.0 / 3.0);
	~WeightedJacobi() = default;
	void IterateOnce(Vector& v) const;
};

std::ostream& operator<<(std::ostream& os, const Vector& v);

#endif